package com.gowants.pems.util;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.ibatis.ognl.Ognl;
import org.apache.ibatis.ognl.OgnlException;
import org.springframework.util.StringUtils;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.apache.commons.beanutils.BeanUtils;

/**
 * 
 * @author GJR
 *
 */
@SuppressWarnings("rawtypes")
public class JSONMap implements Map, Cloneable, Serializable
{

    private static final long serialVersionUID = 1L;
    private static final String CLASS_NAME = "className";
    private JSONObject json;

    public JSONMap()
    {
        json = new JSONObject(16, false);
    }

    @SuppressWarnings("unchecked")
    public JSONMap(Map map)
    {
        json = new JSONObject(map);
    }

    public JSONMap(boolean ordered)
    {
        json = new JSONObject(16, ordered);
    }

    public JSONMap(int initialCapacity)
    {
        json = new JSONObject(initialCapacity, false);
    }

    public JSONMap(int initialCapacity, boolean ordered)
    {
        json = new JSONObject(initialCapacity, ordered);
    }

    /**
     * 解析文本得到JSONMap
     * 
     * @param text
     * @return
     */
    public static final JSONMap parseJSONMap(String text)
    {
        return from(JSONObject.parseObject(text));
    }

    /**
     * 解析文本得到指定的Class对象
     * 
     * @param text
     * @param clazz
     * @return
     */
    public static final <T> T parseObject(String text, Class<T> clazz)
    {
        return JSONObject.parseObject(text, clazz);
    }

    /**
     * 根据ognl表达式express解析text
     * 
     * @param text
     * @param express
     * @return
     */
    @SuppressWarnings("unchecked")
    public static final <T> T parseExpress(String text, String express)
    {
        try
        {
            Object obj = Ognl.getValue(express, JSONMap.parseJSONMap(text));

            if (obj instanceof JSONObject)
            {
                return (T) JSONMap.from((JSONObject) obj);
            }

            if (obj instanceof JSONArray)
            {
                return (T) JSONList.from((JSONArray) obj);
            }
            return (T) obj;
        } 
        catch (OgnlException e)
        {
            throw new RuntimeException(e);
        }
    }

    /**
     * 根据ognl表达式express解析json对象
     * 
     * @param json
     * @param express
     * @return
     */
    @SuppressWarnings("unchecked")
    public static final <T> T parseExpress(JSONMap json, String express)
    {
        try
        {
            Object obj = Ognl.getValue(express, json);
            if (obj instanceof JSONObject)
            {
                return (T) JSONMap.from((JSONObject) obj);
            }

            if (obj instanceof JSONArray)
            {
                return (T) JSONList.from((JSONArray) obj);
            }
            return (T) obj;
        } 
        catch (OgnlException e)
        {
            throw new RuntimeException(e);
        }

    }

    /**
     * JSONMap 转为 纯java对象
     * 
     * @param text
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> T parseComplexJSONMap(String text)
    {
        JSONMap jsonMap = parseJSONMap(text);
        return (T) parseComplexJSONMap(jsonMap);
    }

    /**
     * 解析复杂的JSONMap
     * 
     * @param jsonMap
     * @return
     */
    @SuppressWarnings({ "unchecked" })
    public static <T> T parseComplexJSONMap(JSONMap jsonMap)
    {
        String className = jsonMap.get(CLASS_NAME).toString();

        if (StringUtils.isEmpty(className))
        {
            return (T) jsonMap;
        }

        Class cls;
        Object obj;

        try
        {
            cls = Class.forName(className);
            Method[] ms = cls.getMethods();

            Map<String, Method> writeMethodMap = new HashMap<String, Method>();

            for (Method m : ms)
            {
                writeMethodMap.put(m.getName(), m);
            }

            obj = cls.newInstance();

        } 
        catch (ClassNotFoundException e)
        {
            throw new RuntimeException(className + ":class load error", e);
        } 
        catch (InstantiationException e)
        {
            throw new RuntimeException(className + ":class load error", e);
        } 
        catch (IllegalAccessException e)
        {
            throw new RuntimeException(className + ":class load error", e);
        }

        Iterator<Map.Entry<String, Object>> itr = ((Map) jsonMap).entrySet().iterator();
        while (itr.hasNext())
        {
            Map.Entry<String, Object> entry = itr.next();
            String key = entry.getKey();
            Object value = entry.getValue();
            if (CLASS_NAME.equalsIgnoreCase(key))
            {
                continue;
            }

            if (value instanceof JSONObject)
            {
                try
                {
                    BeanUtils.setProperty(obj, key, parseComplexJSONMap(from((JSONObject) value)));
                } 
                catch (IllegalAccessException e)
                { } 
                catch (InvocationTargetException e)
                { }
                continue;
            }

            if (value instanceof JSONArray)
            {
                try
                {
                    BeanUtils.setProperty(obj, key, JSONList.parseComplexJSONList(JSONList.from((JSONArray) value)));
                } 
                catch (IllegalAccessException e)
                { } 
                catch (InvocationTargetException e)
                { }
                continue;
            }

            try
            {
                BeanUtils.setProperty(obj, key, value);
            } 
            catch (IllegalAccessException e)
            { } 
            catch (InvocationTargetException e)
            { }
            continue;
        }
        return (T) obj;

    }

    /**
     * 将指定的对象转为字符串
     * 
     * @param object
     * @return
     */
    public static final String toJSONString(Object object)
    {
        return JSONObject.toJSONString(object, SerializerFeature.DisableCircularReferenceDetect);
    }

    /**
     * 将fastJSON中的JSONObject对象转为JSONMap对象
     * 
     * @param obj
     * @return
     */
    protected static JSONMap from(JSONObject obj)
    {
        if (null == obj)
        {
            return null;
        }

        JSONMap jobject = new JSONMap();
        jobject.json = obj;
        return jobject;
    }

    /**
     * 获取key值
     * 
     * @param key
     * @return
     */
    public String getValue(String key)
    {
        return getString(key);
    }

    /**
     * 将key对应的值转为JSONMap返回
     * 
     * @param key
     * @return
     */
    public JSONMap getJSONMap(String key)
    {
        return from(json.getJSONObject(key));
    }

    /**
     * 将key对应的值转为JSONList返回
     * 
     * @param key
     * @return
     */
    public JSONList getJSONList(String key)
    {
        return JSONList.from(json.getJSONArray(key));
    }

    /**
     * 将key对应的值转为JSONMap返回
     * 
     * @param key
     * @return
     */
    @SuppressWarnings("unchecked")
    public JSONMap getCanModifyJSOMMap(String key)
    {
        Object obj = json.get(key);
        if (obj instanceof JSONObject)
        {
            return from(json.getJSONObject(key));
        }

        if (obj instanceof Map)
        {
            return JSONMap.from(new JSONObject((Map) obj));
        }

        throw new RuntimeException("getJSONMap获取失败，内部非JSONObject或Map类型!");
    }

    /**
     * 将key对应的值转为JSONList返回
     * 
     * @param key
     * @return
     */
    @SuppressWarnings("unchecked")
    public JSONList getCanModifyJSONList(String key)
    {
        Object obj = json.get(key);

        if (obj instanceof JSONArray)
        {
            return JSONList.from(json.getJSONArray(key));
        }

        if (obj instanceof List)
        {
            return JSONList.from(new JSONArray((List) obj));
        }
        throw new RuntimeException("getJSONList获取失败，内部非JSONArray或List类型！");
    }

    /**
     * 将key对应的值转为指定的Class对象
     * 
     * @param key
     * @return
     */
    public <T> T getObject(String key, Class<T> clazz)
    {
        return json.getObject(key, clazz);
    }

    /**
     * 将key对应的值转为Boolean类型
     * 
     * @param key
     * @return
     */
    public Boolean getBoolean(String key)
    {
        return json.getBoolean(key);
    }

    /**
     * 将key对应的值转为Byte数组类型
     * 
     * @param key
     * @return
     */
    public byte[] getBytes(String key)
    {
        return json.getBytes(key);
    }

    /**
     * 将key对应的值转为boolean类型
     * 
     * @param key
     * @return
     */
    public boolean getBooleanValue(String key)
    {
        return json.getBooleanValue(key);
    }

    /**
     * 将列表中指定位置的值转为Byte类型
     * 
     * @param key
     * @return
     */
    public Byte getByte(String key)
    {
        return json.getByte(key);
    }

    /**
     * 将列表中指定位置的值转为Byte类型
     * 
     * @param key
     * @return
     */
    public byte getByteValue(String key)
    {
        return json.getByteValue(key);
    }

    /**
     * 将列表中指定位置的值转为Short类型
     * 
     * @param key
     * @return
     */
    public Short getShort(String key)
    {
        return json.getShort(key);
    }

    /**
     * 将列表中指定位置的值转为Short类型
     * 
     * @param key
     * @return
     */
    public short getShortValue(String key)
    {
        return json.getShortValue(key);
    }

    /**
     * 将列表中指定位置的值转为Integer类型
     * 
     * @param key
     * @return
     */
    public Integer getInteger(String key)
    {
        return json.getInteger(key);
    }

    /**
     * 将列表中指定位置的值转为int类型
     * 
     * @param key
     * @return
     */
    public int getIntValue(String key)
    {
        return json.getIntValue(key);
    }

    /**
     * 将列表中指定位置的值转为Long类型
     * 
     * @param key
     * @return
     */
    public Long getLong(String key)
    {
        return json.getLong(key);
    }

    /**
     * 将列表中指定位置的值转为long类型
     * 
     * @param key
     * @return
     */
    public long getLongValue(String key)
    {
        return json.getLongValue(key);
    }

    /**
     * 将列表中指定位置的值转为float类型
     * 
     * @param key
     * @return
     */
    public Float getFloat(String key)
    {
        return json.getFloat(key);
    }

    /**
     * 将列表中指定位置的值转为float类型
     * 
     * @param key
     * @return
     */
    public float getFloatValue(String key)
    {
        return json.getFloatValue(key);
    }

    /**
     * 将列表中指定位置的值转为Double类型
     * 
     * @param key
     * @return
     */
    public Double getDouble(String key)
    {
        return json.getDouble(key);
    }

    /**
     * 将列表中指定位置的值转为double类型
     * 
     * @param key
     * @return
     */
    public double getDoubleValue(String key)
    {
        return json.getDoubleValue(key);
    }

    /**
     * 将列表中指定位置的值转为BigDecimal类型
     * 
     * @param key
     * @return
     */
    public BigDecimal getBigDecimal(String key)
    {
        return json.getBigDecimal(key);
    }

    /**
     * <将列表中指定位置的值转为BigInteger类型>
     * 
     * @param key
     * @return
     * @Exception
     * @author guanjingrui 2018年12月24日 上午1:49:46
     * @version 1.0
     */
    public BigInteger getBigInteger(String key)
    {
        return json.getBigInteger(key);
    }

    /**
     * <将列表中指定位置的值转为Double类型>
     * 
     * @param key
     * @return
     * @Exception
     * @author guanjingrui 2018年12月24日 上午1:49:35
     * @version 1.0
     */
    public String getString(String key)
    {
        return json.getString(key);
    }

    /**
     * <将列表中指定位置的值转为java.util.Date类型>
     * 
     * @param key
     * @return
     * @Exception
     * @author guanjingrui 2018年12月24日 上午1:49:26
     * @version 1.0
     */
    public java.util.Date getDate(String key)
    {
        return json.getDate(key);
    }

    /**
     * <将列表中指定位置的值转为java.sql.Date类型>
     * 
     * @param key
     * @return
     * @Exception
     * @author guanjingrui 2018年12月24日 上午1:49:16
     * @version 1.0
     */
    public java.sql.Date getSqlDate(String key)
    {
        return json.getSqlDate(key);
    }

    /**
     * <将列表中指定位置的值转为java.sql.Timestamp类型>
     * 
     * @param key
     * @return
     * @Exception
     * @author guanjingrui 2018年12月24日 上午1:48:52
     * @version 1.0
     */
    public java.sql.Timestamp getTimestamp(String key)
    {
        return json.getTimestamp(key);
    }

    /**
     * <将自己转为JSONString>
     * 
     * @return
     */
    @Override
    public String toString()
    {
        return toJSONString(json);
    }

    /**
     * <将自己转为JSONString>
     * 
     * @return
     */
    public String toJSONString()
    {
        return json.toJSONString();
    }

    @Override
    public int size()
    {
        return json.size();
    }

    @Override
    public boolean isEmpty()
    {
        return json.isEmpty();
    }

    @Override
    public boolean containsKey(Object key)
    {
        return json.containsKey(key);
    }

    @Override
    public boolean containsValue(Object value)
    {
        return json.containsValue(value);
    }

    @Override
    public Object get(Object key)
    {
        return json.get(key);
    }

    @Override
    public Object put(Object key, Object value)
    {
        return json.put((String) key, value);
    }

    @Override
    public Object remove(Object key)
    {
        return json.remove(key);
    }

    @SuppressWarnings("unchecked")
    @Override
    public void putAll(Map m)
    {
        json.putAll(m);
    }

    @Override
    public void clear()
    {
        json.clear();
    }

    @Override
    public Set keySet()
    {
        return json.keySet();
    }

    @Override
    public Collection values()
    {
        return json.values();
    }

    @Override
    public Set entrySet()
    {
        return json.entrySet();
    }

    public Object clone()
    {
        JSONMap jsonMap = null;
        try
        {
            jsonMap = (JSONMap) super.clone();
            jsonMap = (JSONMap) json.clone();
        } 
        catch (CloneNotSupportedException e)
        {
            e.printStackTrace();
        }
        return jsonMap;
    }
}
